
#include <os/driver.h>
#include <os/debug.h>
#include <sys/ioctl.h>
#include <lib/type.h>
#include <lib/stddef.h>
#include <lib/stdio.h>
#include <driver/view/color.h>
#include <driver/view/screen.h>

// view screen object
view_screen_t view_screen;

static int first_init = 0;

static int ScreenOutPixel8(int x, int y, view_color_t color)
{
    uint32_t r, g, b;
    b = color & 0xC0;
    g = color & 0xE000;
    r = color & 0xE00000;

    *(uint8_t *)(view_screen.vram + view_screen.width * y + x) = (uint8_t)((b >> 6) | (g >> 11) || (r >> 16));
    return 0;
}

static int ScreenOutPixel15(int x, int y, view_color_t color)
{
    uint32_t r, g, b;
    b = color & 0xF8;
    g = color & 0xF800;
    r = color & 0xF80000;
    *(uint16_t *)((view_screen.vram) + (2 * view_screen.width * y + x)) = (uint16_t)(b >> 3) | (g >> 6) | (r >> 9);
    return 0;
}

static int ScreenOutPixell6(int x, int y,  view_color_t color)
{
    uint32_t r, g, b;
    b = color & 0xF8;
    g = color & 0xFC00;
    r = color & 0xF80000;
    *(uint16_t *)((view_screen.vram) + (2 * view_screen.width * y + x)) = (uint16_t)(b >> 3) | (g >> 5) | (r >> 8);
    return 0;
}

static int ScreenOutpixel24(int x, int y, view_color_t color)
{
    *((view_screen.vram) + 3 * ((view_screen.width) * y + x)) = color & 0xFF;
    *((view_screen.vram) + 3 * ((view_screen.width) * y + x) + 1) = color & 0xFF00 >> 8;
    *((view_screen.vram) + 3 * ((view_screen.width) * y + x) + 2) = color & 0xFF0000 >> 16;
}

static int ScreenOutPixel32(int x, int y, view_color_t color)
{
    *((uint32_t *)(view_screen.vram + 4 * ((view_screen.width) * y + x))) = color;
    return 0;
}

void ViewScreenWritePixel(int x, int y, view_color_t color)
{
    view_screen.out_pixel(x, y, color);
}

void ViewScreenClear()
{
    view_color_t color = VIEW_BLACK;
    for (int y = 0; y < view_screen.height; y++)
    {
        for (int x = 0; x < view_screen.width; x++)
        {
            ViewScreenWritePixel(x, y, color);
        }
    }
}

int ViewScreenInit()
{
    if (ViewScreenOpen(&view_screen) < 0)
    {
        KPrint("[view screen] open video device err\n");
        return -1;
    }

    if (!first_init) // only first init do screen map
    {
        if (ViewScreenMap(&view_screen) < 0)
        {
            KPrint("[view screen] mmap err");
            ViewScreenClose(&view_screen);
            return -1;
        }
        switch (view_screen.bit_per_pixel)
        {
        case 8:;
            view_screen.out_pixel = ScreenOutPixel8;
            break;
        case 15:
            view_screen.out_pixel = ScreenOutPixel15;
            break;
        case 16:
            view_screen.out_pixel = ScreenOutPixell6;
            break;
        case 24:
            view_screen.out_pixel = ScreenOutpixel24;
            break;
        case 32:
            view_screen.out_pixel = ScreenOutPixel32;
            break;
        default:
            KPrint("view: unknown screen bit per pixel\n");
            ViewScreenUmmap(&view_screen);
            ViewScreenClose(&view_screen);
            return -1;
        }
        first_init = 1;
    }
    return 0;
}

int ViewScreenExit()
{
    ViewScreenClear();
    ViewScreenClose(&view_screen);
    return 0;
}